#    This file is part of robo-ircbot.
#
#    robo-ircbot is free software: you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation, either version 3 of the License, or
#    (at your option) any later version.
#
#    robo-ircbot is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with robo-ircbot.  If not, see <http://www.gnu.org/licenses/>.

package App::Modular::Module::Helper;
use strict;
use warnings;
use XML::Simple;
use base qw(App::Modular::Module);

print ":: Helper module loaded.\n";

# Events we want to receive.
# In this case, we do not want any events, since this module just
# contains useful helper functions.
sub events { return ""; }

sub help {
        return (
                "Helper library that has no interaction with the outside world ".
                "besides this message!"
        );
}

# Returns a hash of a triggers arguments and data or undefined if
# the trigger was not found.
sub trig
{
        my ($self, $name, $e, $req_data) = @_;

        my $data = $e->data;

        my @triggers = (
                '.{trigger}',
                '{trigger}/',
                '!{trigger}',
        );

        my @argvals = (
                ' --{arg}\s*=\s*{val}',
                ' @{arg}\s*=\s*{val}',
                '/{arg}\s*=\s*{val}',
                ' @{arg}\s+{val}',
                ' --{arg}\s+{val}',
                ' @{arg}',
                ' --{arg}',
                '/{arg}',
        );

        my $h = { };
        my ($s, $yes_sir);

        # Look for a trigger.
        foreach (@triggers) {
                $s = $_;
                $s =~ s/([\.\@\$\^\/])/\\$1/g;
                $s =~ s/{trigger}/$name/;

                eval("if (\$data =~ s/^\$s//) { \$yes_sir = 1; }");
        }

        # Check that we had a valid trigger.
        if (!$yes_sir) { return undef; }

        # Remove/store the arguments.
        foreach (@argvals) {
                $s = $_;
                $s =~ s/([\.\@\$\^\/])/\\$1/g;
                $s =~ s/({arg}|{val})/\(\\S+)/g;

                eval("while (\$data =~ s/\$s//) { \$h->{\$1} = \$2; }");
        }

        # Strip leading and trailing whitespace from remaining data.
        $data =~ s/^\s+//; $data =~ s/\s+$//;
        $h->{data} = $data;

        if ($req_data && $data eq '') { return undef; }
        return $h;
}

# Parse out the nick from nick!host format.
sub parse_nick
{
        my ($self, $from) = @_;

        $from =~ /(.+)!.+/;
        return $1;
}

# Parse out the host.
sub parse_host
{
        my ($self, $from) = @_;

        $from =~ /.+!(.+)/;
        return $1;
}

# Check whether we are sending to a channel or nick, if a nick,
# parse the nick with parse_nick().
sub parse_send
{
        my ($self, $to, $from) = @_;

        if ($to =~ /^\#.+/) {
                return $to;
        }

        return parse_nick($self, $from);
}

# Load ignore list.
if (!-e "data/ignore.xml") {
        if (open(IGNORE, ">data/ignore.xml")) {
                print IGNORE "<ignore></ignore>\n";
                close(IGNORE);
        }
}
my $ignore_list;
eval {
        $ignore_list = XMLin("data/ignore.xml");
};
if ($@) { $ignore_list = { }; }

# Write the ignore list to file.
sub write_ignore
{
        open my $fh, ">data/ignore.xml";
        XMLout($ignore_list, OutputFile => $fh, AttrIndent => 1);
        close $fh;
}

# Remove reserved symbols.
sub rem_res
{
        my $str = shift;
        $str =~ s/[\.\@\-]//g;
        return $str;
}

# Switch enabling/disabling of a trigger variable.
# Also implements an ignore system.
sub trigger_switch
{
        my ($self, $modname, $e) = @_;

        my $auth = $e->robo->mod("Auth") || return 0;

        if ($auth->is_authed($e->from)) {
                # Disable module triggers.
                if ($e->data eq ".".$modname." off") {
                        $e->cfg->set_mod($modname."/enabled", 0);
                        $e->s("PRIVMSG ".$e->dest." :".$modname." has been disabled.");
                        return 1;

                # Enable module triggers.
                } elsif ($e->data eq ".".$modname." on") {
                        $e->cfg->set_mod($modname."/enabled", 1);
                        $e->s("PRIVMSG ".$e->dest." :".$modname." has been enabled.");
                        return 1;

                # Add nick/host to ignore list.
                } elsif ($e->data =~ /^.ignore add (\S+)!(\S+)$/) {
                        $e->data(1);

                        my $nick = $1; my $host = rem_res($2);

                        $ignore_list->{$nick} = 1;
                        $ignore_list->{$host} = 1;
                        write_ignore();
                        $e->s("PRIVMSG ".$e->dest." :".$nick."!".$host." was added to the ignore list.");
                        return 1;

                # Remove from ignore list.
                } elsif ($e->data =~ /^.ignore del (\S+)!(\S+)$/) {
                        $e->data(1);

                        my $nick = $1; my $host = rem_res($2);

                        if ($ignore_list->{$nick} && $ignore_list->{$host}) {
                                delete $ignore_list->{$nick};
                                delete $ignore_list->{$host};
                                write_ignore();
                                $e->s("PRIVMSG ".$e->dest." :".$nick."!".$host." was deleted from the ignore list.");
                        } else {
                                $e->s("PRIVMSG ".$e->dest." :".$nick."!".$host." could not be found in the ignore list.");
                        }
                        return 1;

                # List contents of ignore list.
                } elsif ($e->data =~ /^.ignore list$/) {
                        $e->data(1);

                        foreach (keys(%{$ignore_list})) {
                                $e->s("PRIVMSG ".$e->dest." :".$_);
                                sleep(1);
                        }
                        return 1;
                }

        # Module triggers are disabled.
        } elsif (!$e->cfg->get_mod($modname."/enabled")) {
                return 1;

        # User is on the ignore list.
        } elsif ($ignore_list->{rem_res($self->parse_nick($e->from))} || $ignore_list->{rem_res($self->parse_host($e->from))}) {
                return 1;
        }

        return 0;
}

1;
